﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Input;
using Infragistics.Win;
using Infragistics.Win.UltraWinToolbars;
using ScriptEase.Shell.Commands;
using PropertyChangedEventArgs = System.ComponentModel.PropertyChangedEventArgs;



namespace ScriptEase.Shell
{
    /// <summary>
    /// The main window UI dispatcher.
    /// </summary>
    /// <remarks>
    /// The purpose of this class, of "view" classes in general is, to dispatch 
    /// between the user-interface and the underlying ShellViewModel. Basically this functionality
    /// is usually out-of-the-box if you use WPF or Silverlight.
    /// </remarks>
    public partial class ShellView : Form
    {
        public ShellView()
        {
            InitializeComponent();
        }


        private ShellViewModel _viewModel;
        private readonly Dictionary<string, ICommand> _commands = new Dictionary<string, ICommand>();



        /// <summary>
        /// Initializes the ShellView after the viewModel has been created 
        /// but not yet initialized. 
        /// Thus, you cannot use the viewModel's functionality here. But you 
        /// can register/subscribe to the viewModel's events.
        /// </summary>
        public void Initialize(ShellViewModel viewModel)
        {
            // subscribe to viewModel solution collection changes
            _viewModel = viewModel;
            this.Text = _viewModel.GetCaption();

            _viewModel.CrmSolutions.CollectionChanged += crmSolutionsCollectionChanged;
            _viewModel.PropertyChanged += viewModelPropertyChanged;

            _commands.Add("toolProjectNew", new ProjectNewCommand(viewModel));
            _commands.Add("toolConnect", new CrmConnectCommand(viewModel));
            _commands.Add("toolCrmDisconnect", new CrmDisconnectCommand(viewModel));
            _commands.Add("toolProjectOpen", new ProjectOpenCommand(viewModel));
            _commands.Add("toolProjectEdit", new ProjectEditCommand(viewModel));
            _commands.Add("toolProjectClose", new ProjectCloseCommand(viewModel));
            _commands.Add("toolEditProjectXml", new EditProjectXmlCommand(viewModel));
            _commands.Add("toolEditStaticMappingXml", new EditStaticMappingXmlCommand(viewModel));
            _commands.Add("toolGetLatestMerge", new GetLatestMergeCommand(viewModel, this.webResourceStatusList1));
            _commands.Add("toolGetLatestOverwrite", new GetLatestOverwriteCommand(viewModel, this.webResourceStatusList1));

            _commands.Add("toolAutoUpdate", new AutoUpdateCommand(viewModel));
            _commands.Add("toolAutoPublish", new AutoPublishCommand(viewModel));

            _commands.Add("toolUpdateSelected", new UpdateWebResourceCommand(viewModel, this.webResourceStatusList1));
            _commands.Add("toolPublishSelected", new PublishWebResourceCommand(viewModel, this.webResourceStatusList1));
            _commands.Add("toolMergeSelected", new MergeWebResourceCommand(viewModel, this.webResourceStatusList1));
            _commands.Add("toolEditSelected", new EditWebResourceCommand(this.webResourceStatusList1));

            _commands.Add("toolExploreDirectory", new ExploreDirectoryCommand(viewModel, this.webResourceStatusList1));
            _commands.Add("toolExitApplication", new ExitApplicationCommand(viewModel, this.webResourceStatusList1));
            _commands.Add("toolDonate", new DonateCommand());

            this.SolutionSelector.ValueList = new ValueList();
        }



     



        /// <summary>
        /// Initialize the user interface, now that the view has been loaded.
        /// </summary>
        private void shellViewLoaded(object sender, EventArgs e)
        {
            timer1.Start();
        }


        #region UI Controls


        private RibbonTab RibbonTabScript
        {
            get { return this.ultraToolbarsManager1.Ribbon.Tabs["ribbonTabScript"]; }
        }

        private RibbonTab RibbonTabProject
        {
            get { return this.ultraToolbarsManager1.Ribbon.Tabs["ribbonTabProject"]; }
        }

        private ComboBoxTool SolutionSelector
        {
            get { return (ComboBoxTool) this.ultraToolbarsManager1.Tools["toolSolutionSelector"]; }
        }


        #endregion


        #region UI Notification Handlers


        private void listToolValueChanged(object sender, ToolEventArgs e)
        {
            switch (e.Tool.Key)
            {
                case "toolSolutionSelector":
                    // pass the UI change to the underlying viewModel property (like DataBinding)
                    _viewModel.SelectedSolution = _viewModel.CrmSolutions.FirstOrDefault(so => so.UniqueName == (string) this.SolutionSelector.Value);
                    break;
                default:
                    Trace.Default.Warn("No handler for Tool {0} value changes!", e.Tool.Key);
                    break;
            }
        }



        /// <summary>
        /// Tool click or tool value changed event handler
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="ToolClickEventArgs" /> instance containing the event data.</param>
        private void ultraToolbarsManager1ToolClick(object sender, ToolClickEventArgs e)
        {
            try
            {
                ICommand command = _commands[e.Tool.Key];
                if (command.CanExecute(null)) command.Execute(this);
            }
            catch (Exception ex)
            {
                Trace.Default.LogException(ex);
            }
        }



        /// <summary>
        /// Check the ICommand CaneExecute properties on a regular basis..
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void timer1Tick(object sender, EventArgs e)
        {
            foreach (KeyValuePair<string, ICommand> keyValuePair in _commands)
            {
                bool canExecute = keyValuePair.Value.CanExecute(null);
                this.ultraToolbarsManager1.Tools[keyValuePair.Key].SharedProps.Enabled = canExecute;
            }
        }


        #endregion


        #region Model notification handlers


        /// <summary>
        /// Update display when a viewModel property changed
        /// </summary>
        private void viewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "SelectedSolution":
                    this.SolutionSelector.Value = _viewModel.SelectedSolution.UniqueName;
                    break;

                case "ProjectLoadStatus":
                    projectStatusChanged();
                    break;

                default:
                    Trace.Default.Warn("No handler for property {0} changes!", e.PropertyName);
                    break;
            }
        }



        /// <summary>
        /// Handels the viewModel solution-collection changes - like WPF data bound control
        /// </summary>
        /// <remarks>
        /// Update the ComboBox according to the new Solution list.
        /// </remarks>
        private void crmSolutionsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems == null) return;
            foreach (var newItem in e.NewItems)
            {
                Solution newSolution = (Solution) newItem;
                ValueListItem v = this.SolutionSelector.ValueList.FindByDataValue(newSolution.UniqueName);
                if (v == null) this.SolutionSelector.ValueList.ValueListItems.Add(newSolution.UniqueName, newSolution.FriendlyName);
            }
        }



        private void projectStatusChanged()
        {
            #region Thread-safe invoke


            if (this.mainWindowStatusBar.InvokeRequired)
            {
                this.mainWindowStatusBar.Invoke(new MethodInvoker(projectStatusChanged));
                return;
            }

            #endregion


            this.mainWindowStatusBar.Panels[0].Text = _viewModel.ProjectLoadStatus.ToString();

            switch (_viewModel.ProjectLoadStatus)
            {
                case ProjectStatus.Closed:
                    this.mainWindowStatusBar.Panels[1].Text = @"(no project loaded)";
                    this.mainWindowStatusBar.Panels[2].Text = @"disconnected";
                    this.webResourceStatusList1.List = null;

                    this.ultraToolbarsManager1.Ribbon.SelectedTab = this.RibbonTabProject;
                    this.RibbonTabScript.Visible = false;
                    break;


                case ProjectStatus.LoadedDisconnected:
                    this.mainWindowStatusBar.Panels[1].Text = "Project: " + _viewModel.Project.ProjectName;
                    this.mainWindowStatusBar.Panels[2].Text = @"disconnected";
                    this.webResourceStatusList1.List = _viewModel.Project.GetMappings();

                    this.ultraToolbarsManager1.Ribbon.SelectedTab = this.RibbonTabProject;
                    this.RibbonTabScript.Visible = true;
                    this.RibbonTabScript.Groups["ribbonGroupCrm"].Visible = false;
                    this.RibbonTabScript.Groups["ribbonGroupConflictResolution"].Visible = false;

                    StateButtonTool toolAutoUpdate = (StateButtonTool) this.ultraToolbarsManager1.Tools["toolAutoUpdate"];
                    if (toolAutoUpdate.Checked != _viewModel.Project.Data.AutoUpdate) toolAutoUpdate.InitializeChecked(_viewModel.Project.Data.AutoUpdate);
                    StateButtonTool toolAutoPublish = (StateButtonTool) this.ultraToolbarsManager1.Tools["toolAutoPublish"];
                    if (toolAutoPublish.Checked != _viewModel.Project.Data.AutoPublish) toolAutoPublish.InitializeChecked(_viewModel.Project.Data.AutoPublish);
                    break;
                   

                case ProjectStatus.Connected:
                    this.mainWindowStatusBar.Panels[2].Text = "Server: " + _viewModel.Project.ConnectionString.Server;

                    this.RibbonTabScript.Visible = true;
                    this.ultraToolbarsManager1.Ribbon.SelectedTab = this.RibbonTabScript;
                    this.RibbonTabScript.Groups["ribbonGroupCrm"].Visible = true;
                    this.RibbonTabScript.Groups["ribbonGroupConflictResolution"].Visible = true;
                    break;
            }
            this.mainWindowStatusBar.Refresh();  
        }


        #endregion
    }
}